import { Session } from '../src/session';
import { ModelProvider } from '../src/transport';
import { ToolRegistry, Tool } from '../src/tools';
import { InMemoryMemoryStore } from '../src/memory';
import { NodeBuilder, NodeValidator } from '../src/helpers';
import { StructuredNode, NodeType, SendRequest } from '../src/types';

// Advanced custom provider that demonstrates complex scenarios
class AdvancedProvider implements ModelProvider {
  async *generate(req: SendRequest & { requestId: string }): AsyncIterable<StructuredNode> {
    const { requestMessage, requestId } = req;
    
    yield NodeBuilder.thinking(requestId, 'Analyzing your request...');
    
    // Simulate different response patterns based on input
    if (requestMessage.toLowerCase().includes('error')) {
      yield NodeBuilder.rawResponse(requestId, 'I encountered an issue. ');
      yield NodeBuilder.toolUse(requestId, 'debug-tool', { issue: 'simulated error' }, undefined, 'Tool execution failed');
      yield NodeBuilder.rawResponse(requestId, 'Let me try a different approach.');
    } else if (requestMessage.toLowerCase().includes('file')) {
      yield NodeBuilder.rawResponse(requestId, 'I\'ll help you with that file. ');
      yield NodeBuilder.toolUseStart(requestId, 'view', { path: 'example.ts' });
      yield NodeBuilder.toolUse(requestId, 'view', { path: 'example.ts' });
      yield NodeBuilder.rawResponse(requestId, 'File analysis complete. ');
      yield NodeBuilder.agentMemory(requestId, `mem_${Date.now()}`, `User requested file analysis: ${requestMessage}`);
    } else {
      yield NodeBuilder.rawResponse(requestId, 'Thanks for your message. ');
      yield NodeBuilder.rawResponse(requestId, 'Here\'s my response to your query. ');
    }
    
    yield NodeBuilder.suggestedQuestions(requestId, [
      'Can you explain more?',
      'What are the next steps?',
      'How does this work?'
    ]);
    
    yield NodeBuilder.mainTextFinished(requestId);
  }

  async cancel(requestId: string): Promise<void> {
    console.log(`🛑 Cancelled generation for ${requestId}`);
  }
}

// Custom tools for advanced scenarios
const advancedTools: Tool[] = [
  {
    name: 'debug-tool',
    description: 'Debug and analyze issues',
    async run(input: any) {
      const { issue } = input as { issue: string };
      
      // Simulate some processing time
      await new Promise(r => setTimeout(r, 30));
      
      if (issue === 'simulated error') {
        throw new Error('This is a simulated tool error for testing');
      }
      
      return {
        analysis: `Analyzed issue: ${issue}`,
        recommendations: ['Check logs', 'Verify configuration', 'Test in isolation'],
        severity: 'medium'
      };
    }
  },
  {
    name: 'complex-analysis',
    description: 'Perform complex data analysis',
    async run(input: any) {
      const { data, options } = input as { data: any[]; options?: any };
      
      await new Promise(r => setTimeout(r, 50));
      
      return {
        summary: `Analyzed ${data?.length || 0} data points`,
        insights: ['Pattern A detected', 'Anomaly in sector B', 'Trend C confirmed'],
        confidence: 0.85,
        processingTime: '50ms'
      };
    }
  }
];

async function demonstrateAdvancedUsage() {
  console.log('🎓 Advanced Usage Demonstration\n');

  const provider = new AdvancedProvider();
  const tools = new ToolRegistry();
  const memories = new InMemoryMemoryStore();

  // Register advanced tools
  advancedTools.forEach(tool => tools.register(tool));

  // Create session with comprehensive event handling
  const session = new Session({
    model: provider,
    tools,
    memories,
    allowAutoTools: true,
    events: {
      onNode: (turnId, node) => {
        if (NodeValidator.isValidNode(node)) {
          console.log(`✨ Valid node received: ${node.type}`);
        }
      },
      onTurnStatusChange: (turnId, status) => {
        console.log(`🔄 Turn ${turnId.slice(-6)} → ${status}`);
      },
      onError: (turnId, error) => {
        console.log(`💥 Error in turn ${turnId.slice(-6)}: ${error.message}`);
      }
    }
  });

  // Test scenario 1: Normal operation
  console.log('📝 Scenario 1: Normal file analysis request');
  const turn1 = await session.send({ 
    requestMessage: 'Please analyze this file for me',
    modelId: 'advanced-model-v1'
  });

  await new Promise(r => setTimeout(r, 150));

  // Test scenario 2: Error handling
  console.log('\n📝 Scenario 2: Error handling test');
  const turn2 = await session.send({ 
    requestMessage: 'This should trigger an error in the tool'
  });

  await new Promise(r => setTimeout(r, 150));

  // Test scenario 3: Cancellation
  console.log('\n📝 Scenario 3: Cancellation test');
  const turn3 = await session.send({ 
    requestMessage: 'This will be cancelled'
  });

  // Cancel immediately
  session.cancel(turn3);

  await new Promise(r => setTimeout(r, 100));

  // Test scenario 4: Resend functionality
  console.log('\n📝 Scenario 4: Resend functionality');
  const turn4 = await session.resendTurn(turn1);

  await new Promise(r => setTimeout(r, 150));

  // Analysis and reporting
  console.log('\n📊 Session Analysis:');
  const allTurns = session.listTurns();
  
  allTurns.forEach((turn, index) => {
    console.log(`\nTurn ${index + 1} (${turn.id.slice(-6)}):`);
    console.log(`  Status: ${turn.status}`);
    console.log(`  Request: "${turn.requestMessage}"`);
    console.log(`  Nodes: ${turn.nodes.length}`);
    console.log(`  Full text: "${session.getFullText(turn.id)}"`);
    
    const toolResults = session.getToolResults(turn.id);
    if (toolResults.length > 0) {
      console.log(`  Tools used: ${toolResults.map(t => t.tool).join(', ')}`);
    }
    
    const suggestions = session.getSuggestedQuestions(turn.id);
    if (suggestions.length > 0) {
      console.log(`  Suggestions: ${suggestions.join(', ')}`);
    }
  });

  // Memory analysis
  console.log('\n💭 Memory Analysis:');
  const allMemories = [
    ...memories.listByState('pending'),
    ...memories.listByState('accepted'),
    ...memories.listByState('rejected')
  ];
  
  console.log(`Total memories: ${allMemories.length}`);
  allMemories.forEach(mem => {
    console.log(`  ${mem.id} (${mem.state}): "${mem.content}"`);
  });

  // Demonstrate memory operations
  if (allMemories.length > 0) {
    console.log('\n🔄 Testing memory operations...');
    const firstMemory = allMemories[0];
    
    console.log(`Accepting memory: ${firstMemory.id}`);
    memories.updateState(firstMemory.id, 'accepted');
    
    console.log(`Accepted memories: ${memories.listByState('accepted').length}`);
  }
}

demonstrateAdvancedUsage().catch(console.error);
